1

写在前面

一个很难找到问题所在的问题,后来是通过网上的博文才知道了是怎么样的原因,reload(sys)不能随便用,因为一旦重置了,很多环境变量就不一样了。

正文

搞搞编码

首先是问题的来源:

我在写python脚本遇到了下面这个问题

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

相当不能理解,这其实就涉及了python里面相当复杂的编码的问题。在python中运行的字符串都是unicode编码的,为什么需要这么一个中间的编码,其实是很有用的,保证了编码与编码之间的互通性。

首先,大家肯定知道encode和decode,用法如下

str = 'dafd'
unicode_str = str.decode('gb2312') #这表示将gb2312编码的str转化成unicode
unicode_str.encode('utf-8') #这表示将unicode编码的unicode_str转化成utf-8编码

因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码

另外,
代码中字符串的默认编码与代码文件本身的编码一致。记住!~

如:s='中文'

如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,
则其编码为gb2312。这种情况下,要进行编码转换,
都需要先用decode方法将其转换成unicode编码,
再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件。 

如果字符串是这样定义:s=u'中文'

则该字符串的编码就被指定为unicode了,即python的内部编码,
而与代码文件本身的编码无关。因此,对于这种情况做编码转换,只需要直接使用encode方法将其转换成指定编码即可。

如果一个str已经是unicode了,这时候再去decode就会出错,很好理解。

获得系统的默认编码

#!/usr/bin/env python
#coding=utf-8
import sys
print sys.getdefaultencoding()  

该段程序在英文WindowsXP上输出为:ascii 
但其实在ubuntu里也是这样的问题,这其实就是我写这篇文章的初衷,因为我被这个问题困扰了很久!

s = '你好'
print s

输出控制台的编码是ascii时,如果你print的是unicode就会出现这个错误:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

只要改成 print s.encode('utf-8')就ok了。

为什么要reload(sys)

刚刚这么讲好像就解决了?其实不是的,我有个函数tf.train.BytesList,这个函数的参数是一个str,但是这个str的编码因为系统默认编码的原因出错了,就是上面的错。这时候的解决办法一般是reload(sys)。

但是,你会看到卡住了?其实是输出看不到了,网上有这样的解答。


IDLE作为一个GUI Shell环境,在启动初始化过程中,
会设置特定的标准输入、标准输出和标准错误输出,使得输入和输出都在IDLE的GUI Shell中。
而如果手动执行了reload(sys)以后,sys模块的这三个变量将会被重置,
导致输出无法显示在IDLE。所以解决方案很简单,只需要在reload之前把这三个变量都复制一份,reload之后再恢复回来就行了

上面的IDLE其实不只是IDLE,像我就是在jupyter的情况下出错的,terminal下也是一样。所以要记得补上以下代码:

stdi,stdo,stde=sys.stdin,sys.stdout,sys.stderr
reload(sys)
sys.stdin,sys.stdout,sys.stderr=stdi,stdo,stde

ok!就写到这,祝大家coding愉快~


jasperyang
203 声望58 粉丝

Highest purpose is Hacking...